home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #2 / Amiga Plus CD - 1995 - No. 2.iso / internet / faq / englisch / solarisporting < prev    next >
Encoding:
Text File  |  1995-04-11  |  46.1 KB  |  1,288 lines

  1.  
  2.  
  3.  
  4. Archive-name:   Solaris2/porting-FAQ
  5. Last-modified:  Thursday, Feburary 23, 1995
  6. Version:        2.22
  7.  
  8. Solaris 2 Porting FAQ
  9. [Last modified: 23 Feburary 1995]
  10.  
  11. This article contains the answers to some Frequently Asked
  12. Questions (FAQ) often seen in comp.unix.solaris that relate to
  13. porting BSD/Solaris 1 applications to Solaris 2. Over the first
  14. few days of its existence, it has evolved into a more general
  15. discussion about portability among Unix systems, especially as it
  16. relates to BSD, ANSI, POSIX, and SVID compliant systems.  It is
  17. hoped that this document will help reduce volume in this
  18. newsgroup and to provide hard-to-find information of general
  19. interest.
  20.         
  21.         Please redistribute this article!
  22.  
  23. This FAQ is maintained by David Meyer (meyer@ns.uoregon.edu).
  24. Send updates and corrections to me at this address.  It would
  25. help if the subject line contained the phrase "FAQ".
  26.  
  27. This article includes answers to the following questions.  Ones
  28. marked with a + indicate questions new to this issue; those with
  29. changes of content since the last issue are marked by *:
  30.  
  31. 0)  Which preprocessor symbols to use?
  32. 1)  Some Include File Issues
  33. 2)  Libraries
  34. 3)* Possible ANSI/POSIX/SVR4 replacements for some popular BSD functions 
  35. 4)  Signal Primer
  36. 5)  Waiting for Children to Exit
  37. 6)  Dealing with Shadow Password Files
  38. 7)* Some Compatibility Problems
  39. 8)  Other Resources
  40.  
  41. -----------------------------------------------------------------------------
  42. 0) TOPIC: Which preprocessor symbols to use?
  43.  
  44. [Last modified: 11 October 93]
  45.  
  46. [Editor's Note: This section began life as a Solaris 1 and 
  47. Solaris 2 centric discussion. However, it has grown into a more 
  48. generalized portability discussion. I believe that this is a
  49. useful discussion, but it appears that contrasting styles,
  50. preferences, and requirements will make consensus difficult. DM]
  51.  
  52. Answer: This is a difficult and controversial question.
  53.  
  54. In order to understand the following discussion, we need to be
  55. aware of the following standards:
  56.  
  57. ANSI C (ANSI X3J11) 
  58.                 
  59.         This is the standard C definition, originally adopted as
  60.         American National Standard X3.159-1989 and has since been
  61.         adopted as international standard ISO/IEC 9899:1990.
  62.  
  63.                 
  64. POSIX.1 (IEEE 1003.1-1990)
  65.  
  66.         POSIX.1, the Portable Operating System Interface for
  67.         Computer Environments,  is a system level API that deals
  68.         with the function and format of system calls and
  69.         utilities such as signal handling. 
  70.  
  71. SVID3
  72.  
  73.         SVID3, the System V Interface Definition Issue 3, is is
  74.         fully compliant with POSIX.1, and is a arguably subset of
  75.         the SVR4 system API. For example, SVID3 doesn't have
  76.         "-ldl", but many people consider it of the SVR4 API. That
  77.         is, a system could be SVID3-compliant without necessarily
  78.         being an SVR4 system.
  79.  
  80. XPG
  81.  
  82.         XPG, X/Open Company Ltd's X/Open Portability Guide, is a
  83.         broad document which covers a great number of areas,
  84.         including operating systems and programming languages,
  85.         system interfaces, and internetworking. The latest
  86.         version, XPG4, groups these components into "profiles",
  87.         which are packaged together according to market needs.
  88.  
  89.  
  90. Two additional standards are relevant for Suns:
  91.  
  92. SCD 2.0 and x86 ABIs
  93.  
  94.         SCD 2.0 is the SPARC Compliance Definition 2.0. The SCD
  95.         has two components: On the hardware side, 
  96.  
  97.          (i).   System Compliance Test verifies that the hardware
  98.                 and operating system successfully emulates what
  99.                 Sun is doing. It covers low level system issues
  100.                 such as alignment, and linking and loading. 
  101.  
  102.         (ii).   The SPARC Application Verifier tests software to
  103.                 be sure that it runs on SCD hardware. 
  104.  
  105.                 
  106. As an example of subtle differences that exist between the BSD
  107. interface and SVID/POSIX standards, consider the BSD mktemp(3)
  108. call. The SunOS 4.1 mktemp() replaced the trailing X characters
  109. with the letter (e.g., X) and the current process ID. The SVID
  110. and SVR4 versions specify only that the six trailing Xs be
  111. replaced with a character string that can be used to create a
  112. unique filename, and does not depend on the specific name of the
  113. file.  Thus, the BSD and SVR4/SVID3 versions are only
  114. semantically equivalent in the case where only the application
  115. cares that the filename is unique.
  116.  
  117. Now, the basic philosophical question of which preprocessor
  118. contstucts to use here would appear to revolve around the
  119. following choices: 
  120.  
  121.         (i).    Use a high level, large grained standard
  122.                 definition (e.g., _POSIX_SOURCE). In this case,
  123.                 features are implicitly defined. One problem with
  124.                 such definitions is that they may cause other
  125.                 useful functions to become unavailable. However,
  126.                 there are several such definitions in common use.
  127.                 For operating systems, we have
  128.  
  129.                         SVR4
  130.                         SYSV
  131.                         BSD
  132.                         OSF1
  133.  
  134.                 to name a few. For standards, we are mainly
  135.                 interested interested symbols such as 
  136.  
  137.                         __STDC__
  138.                         _POSIX_SOURCE
  139.                         _XOPEN_SOURCE
  140.                 
  141.   
  142.                 This method is not without pitfalls.  For
  143.                 example, the Sun SC2.0.1 compiler defines
  144.                 __STDC__ as 0 when compiling in transition mode
  145.                 (-Xt), only setting it to 1 when the strict ANSI 
  146.                 mode (-Xc) is used. The expression 
  147.  
  148.                         #if (__STDC__ - 0 == 0) 
  149.  
  150.                 can be used to recognize strict v. transition
  151.                 ANSI modes. On Solaris 2, if you compile with
  152.                 -Xc, you will lose all non-ANSI functionality.
  153.                 However, you can define _POSIX_SOURCE or
  154.                 _XOPEN_SOURCE to get a POSIX or XOPEN
  155.                 environment.   
  156.                 
  157.                 If you use _POSIX_SOURCE, .eg., 
  158.                 
  159.                         #define _POSIX_SOURCE 1
  160.  
  161.                 then all symbols not defined by Standard C or the
  162.                 POSIX standard will be hidden (except those with
  163.                 leading underscores). If you wish to use
  164.                 _POSIX_SOURCE, be sure to define it before
  165.                 including any standard header files, and avoid
  166.                 name clashes by not defining any symbols that
  167.                 begin with "_" (Similarly, note that almost all
  168.                 names beginning with  "E" are reserved by
  169.                 errno.h, and many names prefixed by "va_"
  170.                 reserved by stadarg.h). 
  171.  
  172.                 One more note on _POSIX_SOURCE:   SunOS 5.3 has
  173.                 introduced the new header file <sys/feature_tests.h>. 
  174.                 This file is included in all files which have
  175.                 _POSIX_SOURCE dependancies. 
  176.  
  177.                 A new symbol,  _POSIX_C_SOURCE was introduced in POSIX.2
  178.                 (V1 P720, L51) as a mechanism to enable POSIX.1 and
  179.                 POSIX.2 symbols. Its values are as follows:
  180.  
  181.                 /*
  182.                  *      Values of _POSIX_C_SOURCE
  183.                  *
  184.                  *              undefined       not a POSIX compilation
  185.                  *                      1       POSIX.1-1990 compilation
  186.                  *                      2       POSIX.2-1992 compilation
  187.                  *                1993xxL       POSIX.4-1993 compilation
  188.                  */
  189.  
  190.  
  191.                 This means that POSIX.2 says that a value of 1 = POSIX.1
  192.                 and a value of 2 = POSIX.1 & POSIX.2. The idea here is
  193.                 to provide a single control point over the POSIX namespace,
  194.                 rather than having to edit each file individually. 
  195.  
  196.                 Another potential portability pitfall is the
  197.                 __svr4__ feature defined by the FSF (gcc). If you
  198.                 depend on __svr4__, you may lose portability.
  199.                 gcc also defines sun if you don't give the -ansi
  200.                 argument. If you use -ansi,  then sun is not
  201.                 defined and __sun__ is.
  202.  
  203.                 Finally, complexity may arise surrounding a
  204.                 feature which may be part of some vendor's
  205.                 version of some system Y, but may also exist in
  206.                 non-Y compliant systems. Consider, for example,
  207.                 shadow passwording. Systems conforming to the
  208.                 latest SVID (e.g., SVR4) have shadow.h, but there
  209.                 are many systems that have shadow.h without
  210.                 conforming to the SVID.
  211.  
  212.                 So, in general, for code that uses a STD_FEATURE and
  213.                 runs on systems W, Y, and Z, you are left with 
  214.                 something that may look like   
  215.  
  216.                         #if defined(W)                          ||
  217.                            (defined(Y) && _Y_VERSION_ > 3)      ||
  218.                            (defined(Z) || defined(__Z__))
  219.                         #include <STD_FEATURE.h>
  220.                         #endif
  221.  
  222.                 [W, Y, Z are things like SVR4, AIX, NeXT, BSD,
  223.                 and so on. STD_FEATURE.h is something like shadow.h] 
  224.  
  225.                 This example exposes two problems the large
  226.                 grained method. First, it forces one to keep
  227.                 track of exactly which vendors supply
  228.                 <STD_FEATURE.h>.  Second, the complexity of the
  229.                 preprocessor expressions may be a serious
  230.                 consideration, since their complexity is
  231.                 something like     
  232.  
  233.                         O(n*m) where
  234.  
  235.                         n = the number of standard features, and
  236.                         m = number of vendors/systems
  237.  
  238.  
  239.         (ii).   Define new fine-grained feature tests (e.g.,
  240.                 HAVE_POSIX_SIGNALS, or HAVE_SHADOW_H) for
  241.                 features of interest. Such fine-grained features
  242.                 could be used in conjunction with large grained
  243.                 definitions. An nice example of using feature
  244.                 definitions is the GNU configure program. It
  245.                 uses, for example, the features HAVE_BCOPY and
  246.                 HAVE_MEMSET to enable either the bcopy (BSD) or
  247.                 memset (ANSI) functions.   
  248.  
  249.                 Feature testing has the advantage of being useful
  250.                 for automatic configuration with programs such as
  251.                 GNU configure. GNU configure outputs statements
  252.                 of the form
  253.                 
  254.  
  255.                         #define HAVE_aaaa
  256.                         #define HAVE_bbbb
  257.                         #define HAVE_cccc
  258.                         ....
  259.  
  260.                 Another way to generate a feature set is by
  261.                 using the symbol defining the system, e.g., 
  262.  
  263.                         #ifdef SVR4
  264.                         #define HAVE_aaaa
  265.                         #define HAVE_bbbb
  266.                         #define HAVE_cccc
  267.                         ....
  268.  
  269.                         #endif
  270.                         #ifdef BSD43
  271.                         #define HAVE_yyyy
  272.                         ...
  273.                         #endif
  274.                         #ifdef NEWTHING
  275.                         #define HAVE_zzzz
  276.                         ...
  277.                         #endif
  278.         
  279.                 Feature testing also helps to avoid constructs
  280.                 such as 
  281.  
  282.                 #if defined(_POSIX_SOURCE) || defined(_XOPEN_SOURCE)
  283.  
  284.                 [Editor's Note: Finally, an observation: The real
  285.                 issue here appears to be how many of these
  286.                 "features" are migrating to the standard
  287.                 operating systems and interfaces, and how many
  288.                 vendors are implementing these standards. In
  289.                 general, some people feel that feature testing
  290.                 improves portability (and readability), and
  291.                 others believe that the feature testing style 
  292.                 decreases portability and readability. DM]  
  293.  
  294.  
  295.         (iii).  Use some part of the feature's definition itself
  296.                 to enable the feature, for example 
  297.  
  298.                         #ifdef _IOLBF
  299.                                 setvbuf(stderr, NULL, _IOLBF, 0);
  300.                         #else
  301.                                 setlinebuf(stderr);
  302.                         #endif  /* _IOLBF  */
  303.  
  304.                 Note that in this case, another, possibly better
  305.                 option is (consider the case in which some vendor
  306.                 has inadvertently defined _IOLBF for some other
  307.                 purpose):
  308.  
  309.                         #ifdef   __STDC__
  310.                                 setvbuf(stderr, NULL, _IOLBF, 0);
  311.                         #else
  312.                                 setlinebuf(stderr);
  313.                         #endif  /* __STDC__  */
  314.  
  315.                 since setvbuf is required by Standard C.
  316.  
  317.  
  318.  
  319.         Finally, some people have suggested the use of
  320.         expressions like 
  321.  
  322.                 #if defined(sun) && defined(__svr4__)
  323.                         <Solaris 2 centric code>
  324.                 #else 
  325.                         ...
  326.                 #endif
  327.  
  328.  
  329.         As noted above, the __svr4__ feature is defined by the
  330.         FSF (gcc). If you depend on __svr4__, you may lose 
  331.         portability. gcc also defines sun if you don't give the
  332.         -ansi argument. If you use -ansi,  then sun is not
  333.         defined and __sun__ is. The implication here is that
  334.         depending on symbols defined by a given compiler can
  335.         reduce portability.
  336.  
  337.         In general, such a construct should be used if and only if
  338.         the code in question cannot be covered by some standard
  339.         (e.g., SVR4, _POSIX_SOURCE, etc.). Note that it is also
  340.         compiler specific.
  341.         
  342.  
  343. -----------------------------------------------------------------------------
  344. 1) TOPIC: Include File Issues
  345.  
  346. [Last modified: 19 August 93]
  347.  
  348. The first and apparently most common problem is that
  349. /usr/include/strings.h is not ANSI compliant, and as such does not
  350. exist on Solaris 2 (or SVR4). It should be replaced by
  351. /usr/include/string.h, e.g. (following GNU feature definition
  352. conventions)
  353.  
  354.         #if HAVE_STRING_H || defined(STDC_HEADERS)
  355.         #include <string.h>
  356.         #else
  357.         #include <strings.h>
  358.         #endif
  359.         #if defined(STDC_HEADERS)
  360.         #include <stdlib.h>
  361.         #endif /* HAVE_STRING_H */
  362.  
  363.         while ANSI-C requires the name be string.h, one might
  364.         define this as
  365.  
  366.         #ifdef __STDC__
  367.         #include <string.h>
  368.         #else
  369.         #include <strings.h>
  370.         #endif  /* __STDC__ */
  371.  
  372.         However, this again neglects the case in which the vendor 
  373.         provides string.h in a non-ANSI environment.
  374.  
  375.                         
  376. Another thing to watch is for the symbols O_CREAT, O_TRUNC, and
  377. O_EXCL being undefined. On BSD systems, these are defined in
  378. <sys/file.h>. On Solaris 1 systems (beginning with SunOS 4.0) ,
  379. these are defined in <sys/fnctlcom.h> (which is included in
  380. <sys/file.h>). On a POSIX compliant system, these symbols are
  381. defined in <fcntl.h>, which is not included in <sys/file.h>.
  382. Since <fcntl.h> is defined on SunOS 4.1.x, replacing <sys/file.h>
  383. with <fcntl.h> works for both SunOS 4.1.x and SVR4. See, for
  384. example, section 5.3.1.1 of the POSIX spec.
  385.  
  386.  
  387. -----------------------------------------------------------------------------
  388.  
  389. 2) TOPIC: Libraries
  390.  
  391. [Last modified: 12 Feburary 94]
  392.  
  393. Network Libraries:
  394.  
  395. Many of the network functions and definitions that were present
  396. in the BSD libc are now in libnsl.so and libsocket.so. Thus
  397. networking code will generally need to be linked with -lsocket
  398. -lnsl. Since libsocket.so requires libnsl.so (it is NEEDED), you must
  399. specify them in this order. Note that you need libnsl.so for functions
  400. like gethostbyname (see gethostbyname note below). Incidently, you can
  401. look at selected parts of an object file using dump(1), e.g.,  
  402.  
  403.         % dump -Lv /usr/lib/libsocket.so
  404.  
  405.         /usr/lib/libsocket.so:
  406.  
  407.           **** DYNAMIC SECTION INFORMATION ****
  408.         .dynamic :
  409.         [INDEX] Tag      Value
  410.         [1]     NEEDED   libnsl.so.1
  411.         [2]     INIT     0x3174
  412.  
  413.         [...]
  414.         
  415. Regular Expressions
  416.  
  417. Another problem frequently encountered is that the regexp
  418. functions (see regexpr(3G)) are not defined in libc. On Solaris
  419. 2, you must link with libgen.a (-lgen) in order to get these
  420. definitions. See Intro(3) for a more complete discussion.
  421.  
  422. Name List (nlist)
  423.  
  424. You must link with libelf.a (-lelf) to get the nlist(3E)
  425. definition. 
  426.  
  427. -----------------------------------------------------------------------------
  428.  
  429. 3)* TOPIC: Possible ANSI/POSIX/SVR4 replacements for some popular
  430.            BSD functions  
  431.  
  432. [Last modified: 23 Feburary 1995]
  433.  
  434. [Editor's Note: Once again, this section began life a SunOS 4.1.x 
  435. and SunOS 5.x centric discussion.  It too has grown into a
  436. discussion dealing with general portability for BSD to other
  437. standards. DM]
  438.  
  439. Problems finding functions that were defined in the BSD libc.a is
  440. one of the most frequently asked porting questions. The following
  441. table and code fragments suggest substitutes for some common BSD
  442. constructs (more complete lists can be found in some of the texts
  443. listed in section 7 below). 
  444.  
  445. In addtion to the possibilites listed below, many people have 
  446. created compatability libraries using GNU autoconfigure. An
  447. example of this is the "generic" libary from Dan Stromberg
  448. (strombrg@hydra.acs.uci.edu). It can be found on 
  449. ftp.uci.edu:/pub/generic/generic.tar.gz.
  450.  
  451.  
  452. BSD                     Possibilities           Standards/Notes
  453. ============================================================================
  454. srandom(seed)           srand(seed)             ANSI-C (Also, some older UNIX)
  455.                         srand48(seed)           SVR4
  456.  
  457. non-ANSI signal()       sigset()                SVR4   (systems calls not
  458. (e.g., SunOS)                                          restarted, but bytes r/w
  459.                                                        returned, else EINTR) 
  460.                         sigaction               POSIX  (but extensible by
  461.                                                        implementation) 
  462.  
  463. sigvec                  sigaction               POSIX
  464. sigblock                sigprocmask             POSIX
  465.                         sigset(.., SIG_HOLD)
  466.                         sighold                 SVR4
  467. sigsetmask              sigprocmask             POSIX
  468.                         sigset/sigrelse         SVR4    
  469.  
  470. sigpause                sigsuspend              POSIX
  471.         
  472. setjmp                  sigsetjmp               POSIX 
  473. longjmp                 siglongjmp              POSIX 
  474.  
  475. statfs                  statvfs                 SVR4
  476.  
  477. bcopy                   memmove                 ANSI-C (BSD bcopy() handles
  478.                                                        overlapping areas
  479.                                                        correctly, as does
  480.                                                        memmove, but not memcpy)
  481.  
  482. bzero                   memset                  ANSI-C
  483.  
  484. index                   strchr                  ANSI-C
  485. rindex                  strrchr                 ANSI-C
  486.  
  487. getwd                   getcwd                  POSIX
  488.  
  489. getrusage               open,ioctl              The getrusage information
  490.                                                 (and a whole lot more) can be
  491.                                                 found in the prusage structure.
  492.                                                 Use the PIOCUSAGE ioctl. See
  493.                                                 the example below and the
  494.                                                 proc(4) man page for detail. 
  495.  
  496.  
  497. gethostname             sysinfo(SI_HOSTNAME,..) SVR4   See sysinfo(2) for
  498.                                                        many other possible
  499.                                                        values
  500.  
  501. getdtablesize           sysconf(_SC_OPEN_MAX)   POSIX  See sysconf(3C) for
  502.                                                        many other values
  503.                                                        available via sysconf.
  504.  
  505. strptime                                                See code from Kevin Ruddy
  506.                                                         below
  507.  
  508. timelocal               mktime                          
  509.  
  510. wait3 w/o rusage        waitpid                 POSIX
  511. wait3                   waitid                  SVR4
  512.  
  513. usleep                   nanosleep              POSIX See nanosleep(3R) on
  514.                                                 Solaris 2.3 (see libposix4.a) 
  515.                                                 For a Solaris 2.[0-2], see the
  516.                                                 example below.
  517.  
  518.  
  519.  
  520.  
  521. ------------------------------------------------------------------
  522.  
  523.         Some Well-Traveled Macros
  524.         -------------------------
  525.  
  526.         #define bcopy(src,dest,len)     (memmove((dest), (src), (len)))
  527.         #define bzero(dest,len)         (memset((dest), (char)0, (len)))
  528.         #define bcmp(b1,b2,n)           (memcmp((b1),(b2),(n)))
  529.         #define index(s,c)              strchr((s),(c))
  530.         #define rindex(s,c)             strrchr((s),(c))
  531.         #define MIN(a, b)               ((a) < (b) ? (a) : (b))
  532.         #define MAX(a, b)               ((a) < (b) ? (b) : (a))
  533.         #ifdef  MAXPATHLEN
  534.         #define getwd(x)                getcwd((x), MAXPATHLEN)
  535.         #endif  /* MAXPATHLEN */
  536.         define  setlinebuf(fp)          setvbuf(fp, NULL, _IOLBF, 0);
  537.  
  538.  
  539.         Timing Problems
  540.         ---------------
  541.  
  542.         POSIX defines the <sys/times.h> function for subsecond
  543.         timing.  Sun seems to provide about 1/60 second accuracy. 
  544.  
  545.         #include <stdio.h>
  546.         #include <sys/times.h>   /* for struct tms and times() */
  547.         #include <time.h>        /* for CLK_TCK value */
  548.  
  549.         int main(void) {
  550.            struct tms tms_start, tms_finish;  /* user and system time */
  551.            clock_t start, finish;             /* real time */
  552.            start = times( &tms_start );
  553.            /* ... do something ... */
  554.            finish = times( &tms_finish );
  555.            printf("(in seconds) %f real, %f system, %f user\n",
  556.                (finish-start) / (double)CLK_TCK,
  557.                (tms_finish.tms_stime-tms_start.tms_stime) / (double)CLK_TCK,
  558.                (tms_finish.tms_utime-tms_start.tms_utime) / (double)CLK_TCK);
  559.            return 0;
  560.         }
  561.  
  562.         You might want to divide CLK_TCK by 1000.0 to get more
  563.         precise millisecond values.  times() returns -1 if it
  564.         cannot provide timing information.
  565.  
  566.         While Solaris 2 conforms to POSIX, SunOS 4.1 defines
  567.         times() as returning a flag instead of elapsed real time.
  568.         You can use ftime() to get elapsed real time:
  569.  
  570.         #include <stdio.h>
  571.         #include <sys/types.h>  /* for time_t */
  572.         #include <sys/timeb.h>  /* for ftime() and struct timeb */
  573.  
  574.         int main(void) {
  575.            struct timeb start, finish;
  576.            double real_secs;
  577.            ftime( &start );
  578.            /* ... do something ... */
  579.            ftime( &finish );
  580.            real_secs = finish.time - start.time;
  581.            if ( finish.millitm < start.millitm )
  582.               real_secs = (real_secs-1) +
  583.                           (1000+start.millitm-finish.millitm)/1000.0;
  584.            else
  585.               real_secs = (finish.millitm-start.millitm)/1000.0;
  586.            printf( "That took %f real seconds.", real_secs );
  587.            return 0;
  588.         }
  589.  
  590.         The ANSI C function clock() can also be used for timing.
  591.         It returns elased "processor" time, which is equivalent
  592.         to system+user time. While it also returns a clock_t
  593.         value, you must divide the difference between to calls to
  594.         clock() by CLOCKS_PER_SEC, *not* CLK_TCK.  The values are
  595.         different by orders of magnitude.  SunOS 4.1 doesn't seem
  596.         to provide CLOCKS_PER_SEC or CLK_TCK in <time.h>.  Try
  597.         10000000 and 60, respectively.
  598.  
  599.  
  600.  
  601.         Compatibility Functions
  602.         -----------------------
  603.  
  604.         /*
  605.          *      getrusage --
  606.          */
  607.  
  608.         #include <sys/resource.h>
  609.         #ifndef RUSAGE_SELF
  610.         #include <sys/procfs.h>
  611.         #endif
  612.  
  613.         #ifdef PIOCUSAGE
  614.                 int             fd;
  615.                 char            proc[SOMETHING];
  616.                 prusage_t       prusage;
  617.  
  618.                 sprintf(proc,"/proc/%d", getpid());
  619.                 if ((fd = open(proc,O_RDONLY)) == -1) {
  620.                         perror("open");
  621.                         ....
  622.                 }
  623.                 if (ioctl(fd, PIOCUSAGE, &prusage) == -1) {
  624.                         perror("ioctl");
  625.                         ...
  626.                 }
  627.                 ....
  628.         #else                   /* Again, assume BSD */
  629.                 if (getrusage(RUSAGE_SELF, &rusage) == -1) {
  630.                         perror("getrusage");
  631.                         ....
  632.                 }
  633.                 ....
  634.         #endif /* PIOCUSAGE */
  635.  
  636.  
  637.  
  638.         /*
  639.          *      setlinebuf --
  640.          *
  641.          */
  642.         
  643.         #ifdef   __STDC__
  644.                 setvbuf(stderr, NULL, _IOLBF, 0);
  645.         #else
  646.                 setlinebuf(stderr);
  647.         #endif  /* __STDC__  */
  648.  
  649.  
  650.         /*
  651.          *      gethostid 
  652.          *
  653.          *      This example has a combination of high-level
  654.          *      (SVR4) and (SI_HW_SERIAL) feature declarations.
  655.          */
  656.         
  657.         #if defined(SVR4) && defined(SI_HW_SERIAL)
  658.         long  gethostid() {
  659.                         
  660.           char buf[128];
  661.                 
  662.           if (sysinfo(SI_HW_SERIAL, buf, 128) == -1) {
  663.             perror("sysinfo");
  664.             exit(1);
  665.           }
  666.           return(strtoul(buf,NULL,0));
  667.         }
  668.         #endif /* SVR4 && SI_HW_SERIAL */
  669.  
  670.  
  671.         /*
  672.          *      getdtablesize --
  673.          *
  674.          *      Several possibilites here. Note that while one
  675.          *      can emulate getdtablesize with getrlimit on SVR4
  676.          *      or 4.3BSD (or later), these systems should be
  677.          *      POSIX.1 compliant, so sysconf is preferred.
  678.          *
  679.          */
  680.  
  681.         #ifdef  _SC_OPEN_MAX            /* POSIX -- preferred */
  682.                 if ((tableSize = sysconf(_SC_OPEN_MAX)) == -1) {
  683.                         perror("sysconf");
  684.                         ...
  685.                 }
  686.         #elif   RLIMIT_NOFILE           /* who is non POSIX but has this? */
  687.                 if (getrlimit(RLIMIT_NOFILE, &rlimit) == -1) {
  688.                         perror("getrlimit");
  689.                         exit(1);
  690.                 }
  691.                 tableSize = rlimit.rlim_max;
  692.         #else                           /* assume old BSD type */
  693.                 tableSize = getdtablesize();
  694.         #endif
  695.  
  696.  
  697. ------------------   
  698.  
  699.         /*
  700.          * gethostname  --
  701.          *
  702.          */
  703.  
  704.         #ifdef  SVR4 
  705.         #include <sys/systeminfo.h>
  706.         #endif  /* SVR4 */ 
  707.  
  708.                 ....
  709.  
  710.                 char buf[MAXHOSTNAME]
  711.  
  712.         #ifdef  SVR4
  713.                 if (sysinfo(SI_HOSTNAME, buf, sizeof(buf)) <0) {
  714.                         perror("SI_HOSTNAME");
  715.                         exit(BAD);
  716.                 }
  717.         #else   /* Assume BSD */
  718.                 if (gethostname(buf, sizeof(buf)) < 0) {
  719.                         perror("gethostname");
  720.                         exit(BAD);
  721.                 }
  722.         #endif  /* SVR4 */
  723.  
  724.         /* buf has hostname here... */
  725.  
  726.  
  727.         /*
  728.          *      usleep(delay)  --
  729.          *
  730.          *      Possible usleep replacement. Delay in microseconds.
  731.          *      Another possiblity is to use poll(2). On Solaris
  732.          *      2.x, select is just a wrapper for poll, so you
  733.          *      are better off using it directly.  If you use,
  734.          *      poll, note that it uses millisecond resolution,
  735.          *      and is not affected by the O_NDELAY and O_NONBLOCK 
  736.          *      flags.
  737.          *
  738.          *      Note that using nanosleep has portability implications,
  739.          *      even across different versions of Solaris 2.x. In
  740.          *      particular, only Solaris 2.3 has libposix4, and 
  741.          *      hence nanosleep. Select (or poll) is a better option if 
  742.          *      you need portability across those versions.
  743.          *
  744.          *      If you define USE_NANOSLEEP, be sure to link with -lposix4
  745.          *
  746.          */
  747.  
  748.         #include <unistd.h>
  749.         #include <stdlib.h>
  750.         #include <stdio.h>
  751.         #include <errno.h>
  752.         #include <time.h>
  753.         #include <sys/time.h>
  754.         #include <sys/param.h>
  755.         #include <sys/types.h>
  756.         #ifdef  USE_POLL
  757.         #include <stropts.h>
  758.         #include <poll.h>
  759.         #endif  /* USE_POLL */
  760.         
  761.         int     usleep(unsigned long int useconds)
  762.         {
  763.         #ifdef  USE_NANOSLEEP
  764.           struct timespec rqtp;
  765.         
  766.           rqtp.tv_sec  = useconds / (unsigned long)  1000000;
  767.           rqtp.tv_nsec = (useconds % (unsigned long) 1000000) * 1000 ;
  768.         
  769.           if (nanosleep(&rqtp,  (struct  timespec *) NULL) == -1)
  770.             perror("nanosleep");
  771.           return (0);
  772.         
  773.         #elif   USE_POOL
  774.           struct pollfd unused;
  775.         
  776.           if (poll(&unused,0,(useconds/1000)) == -1) 
  777.             perror("poll");
  778.           return(0);
  779.         #elif   USE_USLEEP
  780.           struct timeval delay;
  781.         
  782.           delay.tv_sec = 0;
  783.           delay.tv_usec = useconds;
  784.           if (select(0,
  785.                      (fd_set *) NULL,
  786.                      (fd_set *) NULL,
  787.                      (fd_set *) NULL,
  788.                      &delay) == -1)
  789.             perror("select");
  790.           return (0);
  791.         #endif                  /* USE_NANOSLEEP */
  792.         
  793.         
  794.         /*
  795.          *      tzsetwall -- 
  796.          */
  797.         
  798.         void tzsetwall()
  799.         {
  800.           unsetenv("TZ");
  801.           tzset();
  802.         }
  803.  
  804.         /*
  805.          *      gethostybname --
  806.          *
  807.          *      The following code was contributed by Casper H.S. Dik
  808.          *      to address the following problem:
  809.          *
  810.          *      gethostbyname() always returns null in h->aliases.
  811.          *      Now, gethostbyX can be replaced its __switch_gethostbyX
  812.          *      equivalents. However, these are missing from Solaris 2.3.
  813.          *
  814.          *      The _r functions are reentrant.  They have a different
  815.          *      calling sequence. (The __switch_getXXXbyYYY are called
  816.          *      like getXXXbyYYY, the _switch_getXXXbyYYY_r are called
  817.          *      like getXXXbyYYY_r) 
  818.          *
  819.          *      With this bit of knowledge I constructed the code that
  820.          *      follows this message. Just plug it in every program
  821.          *      that requires gethostbyname to work. (Gethostbyaddr()
  822.          *      is added for symmetry). 
  823.          *
  824.          *      You'll need to link with -lnsl -ldl.
  825.          *
  826.          *      It works for Solaris 2.2 and 2.3.  (Compiled on 2.3 or
  827.          *      2.2 it will run 2.2 and 2.3)
  828.          *
  829.          *      Note that as with __switch* _switch*_r is undocumented
  830.          *      and can be changed in the next release.
  831.          *
  832.          */
  833.         
  834.         /*
  835.          *     Proper gethostbyXX function for Solaris 2.0-2.3
  836.          *     (and later ?) 
  837.          *
  838.          *     Fixed in 2.4?
  839.          *
  840.          *     You'll need -ldl added to the link command line.
  841.          *
  842.          *     Casper Dik (casper@fwi.uva.nl)
  843.          *
  844.          */
  845.  
  846.         #include <netdb.h>
  847.         #include <dlfcn.h>
  848.         
  849.         #define HBUFSIZE 4096
  850.         
  851.         static void *dlhandle;
  852.         /* The gethostbyXXX function variables. Named after
  853.         * then .so files they appear in. nsw*.so in SunOS 5.2
  854.         * and earlier, nss_*.so in 5.3 */ 
  855.         static struct hostent *(*nswghba)(const char *, int, int),
  856.                               *(*nswghbn)(const char *),
  857.                               *(*nss_ghba)(const char *,
  858.                                            int, int,
  859.                                            struct hostent *, char *, int, int *),
  860.                               *(*nss_ghbn)(const char *,
  861.                                            struct hostent *, char *, int, int *);
  862.         
  863.         static int dlinit(void)
  864.         {
  865.           static int dlstatus = 0; /* 0 = uninited, 1 = inited & ok, -1 = error */
  866.         
  867.           if (dlstatus)
  868.             return dlstatus;
  869.         
  870.           dlstatus = -1;
  871.         
  872.           dlhandle = dlopen(0, RTLD_LAZY);
  873.         
  874.           if (dlhandle == 0)
  875.             return dlstatus;
  876.         
  877.           /* SunOS 5.0 - 5.2 */
  878.           nswghba = (struct hostent *(*)(const char *, int, int))
  879.             dlsym(dlhandle, "__switch_gethostbyaddr");
  880.         
  881.           nswghbn = (struct hostent *(*)(const char *))
  882.             dlsym(dlhandle, "__switch_gethostbyname");
  883.         
  884.           /* either both should exist or both should not exist */
  885.           if ((nswghbn == 0) != (nswghba == 0))
  886.             return dlstatus;
  887.         
  888.           if (nswghbn)
  889.             return dlstatus = 1;
  890.         
  891.           /* SunOS 5.3 - ? */
  892.           nss_ghba = (struct hostent *(*)
  893.                       (const char *, int, int, struct hostent *, char *, int , int *))
  894.             dlsym(dlhandle, "_switch_gethostbyaddr_r");
  895.         
  896.           nss_ghbn = (struct hostent *(*)
  897.                       (const char *, struct hostent *, char *, int , int *))
  898.             dlsym(dlhandle, "_switch_gethostbyname_r");
  899.         
  900.           /* these two must exist when we get here */
  901.           if (nss_ghbn != 0 && nss_ghba != 0)
  902.             dlstatus = 1;
  903.         
  904.           return dlstatus;
  905.         }
  906.         
  907.         struct hostent *
  908.         gethostbyname(const char *name) {
  909.         
  910.           static struct hostent hp;
  911.           static char buf[HBUFSIZE];
  912.         
  913.           if (dlinit() == -1)
  914.             return 0;
  915.         
  916.           if (nswghbn)
  917.             return nswghbn(name);
  918.           else
  919.             return nss_ghbn(name, &hp, buf, sizeof(buf), &h_errno);
  920.         }
  921.         
  922.         struct hostent *
  923.         gethostbyaddr(const char *addr, int len, int type) {
  924.           static struct hostent hp;
  925.           static char buf[HBUFSIZE];
  926.         
  927.           if (dlinit() == -1)
  928.             return 0;
  929.         
  930.           if (nswghba)
  931.             return nswghba(addr, len, type);
  932.           else
  933.             return nss_ghba(addr,
  934.                             len, type, &hp, buf, sizeof(buf), &h_errno);
  935.         }
  936.  
  937.  
  938. ------------------   
  939. strptime
  940. -----------------
  941.  
  942. /*
  943.  * Copyright (c) 1994 Powerdog Industries.  All rights reserved.
  944.  *
  945.  * Redistribution and use in source and binary forms, without
  946.  * modification, are permitted provided that the following conditions
  947.  * are met:
  948.  * 1. Redistributions of source code must retain the above copyright
  949.  *    notice, this list of conditions and the following disclaimer.
  950.  * 2. Redistributions in binary form must reproduce the above copyright
  951.  *    notice, this list of conditions and the following disclaimer
  952.  *    in the documentation and/or other materials provided with the
  953.  *    distribution.
  954.  * 3. All advertising materials mentioning features or use of this
  955.  *    software must display the following acknowledgement:
  956.  *      This product includes software developed by Powerdog Industries.
  957.  * 4. The name of Powerdog Industries may not be used to endorse or
  958.  *    promote products derived from this software without specific prior
  959.  *    written permission.
  960.  *
  961.  * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
  962.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  963.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  964.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
  965.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  966.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  967.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  968.  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  969.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  970.  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  971.  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  972.  */
  973.  
  974. #ifndef lint
  975. static char copyright[] =
  976. "@(#) Copyright (c) 1994 Powerdog Industries.  All rights reserved.";
  977. static char sccsid[] = "@(#)strptime.c  0.1 (Powerdog) 94/03/27";
  978. #endif /* not lint */
  979.  
  980. #include <time.h>
  981. #include <ctype.h>
  982. #include <locale.h>
  983. #include <string.h>
  984.  
  985. #define asizeof(a)      (sizeof (a) / sizeof ((a)[0]))
  986.  
  987. #ifndef sun
  988. struct dtconv {
  989.         char    *abbrev_month_names[12];
  990.         char    *month_names[12];
  991.         char    *abbrev_weekday_names[7];
  992.         char    *weekday_names[7];
  993.         char    *time_format;
  994.         char    *sdate_format;
  995.         char    *dtime_format;
  996.         char    *am_string;
  997.         char    *pm_string;
  998.         char    *ldate_format;
  999. };
  1000. #endif
  1001.  
  1002. static struct dtconv    En_US = {
  1003.         { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1004.           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" },
  1005.         { "January", "February", "March", "April",
  1006.           "May", "June", "July", "August",
  1007.           "September", "October", "November", "December" },
  1008.         { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
  1009.         { "Sunday", "Monday", "Tuesday", "Wednesday",
  1010.           "Thursday", "Friday", "Saturday" },
  1011.         "%H:%M:%S",
  1012.         "%m/%d/%y",
  1013.         "%a %b %e %T %Z %Y",
  1014.         "AM",
  1015.         "PM",
  1016.         "%A, %B, %e, %Y"
  1017. };
  1018.  
  1019. #ifdef SUNOS4
  1020. extern int      strncasecmp();
  1021. #endif
  1022.  
  1023. char    *
  1024. strptime(char *buf, char *fmt, struct tm *tm)
  1025. {
  1026.         char    c,
  1027.                 *ptr;
  1028.         int     i,
  1029.                 len;
  1030.  
  1031.         ptr = fmt;
  1032.         while (*ptr != 0) {
  1033.                 if (*buf == 0)
  1034.                         break;
  1035.  
  1036.                 c = *ptr++;
  1037.  
  1038.                 if (c != '%') {
  1039.                         if (isspace(c))
  1040.                                 while (*buf != 0 && isspace(*buf))
  1041.                                         buf++;
  1042.                         else if (c != *buf++)
  1043.                                 return 0;
  1044.                         continue;
  1045.                 }
  1046.  
  1047.                 c = *ptr++;
  1048.                 switch (c) {
  1049.                 case 0:
  1050.                 case '%':
  1051.                         if (*buf++ != '%')
  1052.                                 return 0;
  1053.                         break;
  1054.  
  1055.                 case 'C':
  1056.                         buf = strptime(buf, En_US.ldate_format, tm);
  1057.                         if (buf == 0)
  1058.                                 return 0;
  1059.                         break;
  1060.  
  1061.                 case 'c':
  1062.                         buf = strptime(buf, "%x %X", tm);
  1063.                         if (buf == 0)
  1064.                                 return 0;
  1065.                         break;
  1066.  
  1067.                 case 'D':
  1068.                         buf = strptime(buf, "%m/%d/%y", tm);
  1069.                         if (buf == 0)
  1070.                                 return 0;
  1071.                         break;
  1072.  
  1073.                 case 'R':
  1074.                         buf = strptime(buf, "%H:%M", tm);
  1075.                         if (buf == 0)
  1076.                                 return 0;
  1077.                         break;
  1078.  
  1079.                 case 'r':
  1080.                         buf = strptime(buf, "%I:%M:%S %p", tm);
  1081.                         if (buf == 0)
  1082.                                 return 0;
  1083.                         break;
  1084.  
  1085.                 case 'T':
  1086.                         buf = strptime(buf, "%H:%M:%S", tm);
  1087.                         if (buf == 0)
  1088.                                 return 0;
  1089.                         break;
  1090.  
  1091.                 case 'X':
  1092.                         buf = strptime(buf, En_US.time_format, tm);
  1093.                         if (buf == 0)
  1094.                                 return 0;
  1095.                         break;
  1096.  
  1097.                 case 'x':
  1098.                         buf = strptime(buf, En_US.sdate_format, tm);
  1099.                         if (buf == 0)
  1100.                                 return 0;
  1101.                         break;
  1102.  
  1103.                 case 'j':
  1104.                         if (!isdigit(*buf))
  1105.                                 return 0;
  1106.  
  1107.                         for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
  1108.                                 i *= 10;
  1109.                                 i += *buf - '0';
  1110.                         }
  1111.                         if (i > 365)
  1112.                                 return 0;
  1113.  
  1114.                         tm->tm_yday = i;
  1115.                         break;
  1116.  
  1117.                 case 'M':
  1118.                 case 'S':
  1119.                         if (*buf == 0 || isspace(*buf))
  1120.                                 break;
  1121.  
  1122.                         if (!isdigit(*buf))
  1123.                                 return 0;
  1124.  
  1125.                         for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
  1126.                                 i *= 10;
  1127.                                 i += *buf - '0';
  1128.                         }
  1129.                         if (i > 59)
  1130.                                 return 0;
  1131.  
  1132.                         if (c == 'M')
  1133.                                 tm->tm_min = i;
  1134.                         else
  1135.                                 tm->tm_sec = i;
  1136.  
  1137.                         if (*buf != 0 && isspace(*buf))
  1138.                                 while (*ptr != 0 && !isspace(*ptr))
  1139.                                         ptr++;
  1140.                         break;
  1141.  
  1142.                 case 'H':
  1143.                 case 'I':
  1144.                 case 'k':
  1145.                 case 'l':
  1146.                         if (!isdigit(*buf))
  1147.                                 return 0;
  1148.  
  1149.                         for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
  1150.                                 i *= 10;
  1151.                                 i += *buf - '0';
  1152.                         }
  1153.                         if (c == 'H' || c == 'k') {
  1154.                                 if (i > 23)
  1155.                                         return 0;
  1156.                         } else if (i > 11)
  1157.                                 return 0;
  1158.  
  1159.                         tm->tm_hour = i;
  1160.  
  1161.                         if (*buf != 0 && isspace(*buf))
  1162.                                 while (*ptr != 0 && !isspace(*ptr))
  1163.                                         ptr++;
  1164.                         break;
  1165.  
  1166.                 case 'p':
  1167.                         len = strlen(En_US.am_string);
  1168.                         if (strncasecmp(buf, En_US.am_string, len) == 0) {
  1169.                                 if (tm->tm_hour > 12)
  1170.                                         return 0;
  1171.                                 if (tm->tm_hour == 12)
  1172.                                         tm->tm_hour = 0;
  1173.                                 buf += len;
  1174.                                 break;
  1175.                         }
  1176.  
  1177.                         len = strlen(En_US.pm_string);
  1178.                         if (strncasecmp(buf, En_US.pm_string, len) == 0) {
  1179.                                 if (tm->tm_hour > 12)
  1180.                                         return 0;
  1181.                                 if (tm->tm_hour != 12)
  1182.                                         tm->tm_hour += 12;
  1183.                                 buf += len;
  1184.                                 break;
  1185.                         }
  1186.  
  1187.                         return 0;
  1188.  
  1189.                 case 'A':
  1190.                 case 'a':
  1191.                         for (i = 0; i < asizeof(En_US.weekday_names); i++) {
  1192.                                 len = strlen(En_US.weekday_names[i]);
  1193.                                 if (strncasecmp(buf,
  1194.                                                 En_US.weekday_names[i],
  1195.                                                 len) == 0)
  1196.                                         break;
  1197.  
  1198.                                 len = strlen(En_US.abbrev_weekday_names[i]);
  1199.                                 if (strncasecmp(buf,
  1200.                                                 En_US.abbrev_weekday_names[i],
  1201.                                                 len) == 0)
  1202.                                         break;
  1203.                         }
  1204.                         if (i == asizeof(En_US.weekday_names))
  1205.                                 return 0;
  1206.  
  1207.                         tm->tm_wday = i;
  1208.                         buf += len;
  1209.                         break;
  1210.  
  1211.                 case 'd':
  1212.                 case 'e':
  1213.                         if (!isdigit(*buf))
  1214.                                 return 0;
  1215.  
  1216.                         for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
  1217.                                 i *= 10;
  1218.                                 i += *buf - '0';
  1219.                         }
  1220.                         if (i > 31)
  1221.                                 return 0;
  1222.  
  1223.                         tm->tm_mday = i;
  1224.  
  1225.                         if (*buf != 0 && isspace(*buf))
  1226.                                 while (*ptr != 0 && !isspace(*ptr))
  1227.                                         ptr++;
  1228.                         break;
  1229.  
  1230.                 case 'B':
  1231.                 case 'b':
  1232.                 case 'h':
  1233.                         for (i = 0; i < asizeof(En_US.month_names); i++) {
  1234.                                 len = strlen(En_US.month_names[i]);
  1235.                                 if (strncasecmp(buf,
  1236.                                                 En_US.month_names[i],
  1237.                                                 len) == 0)
  1238.                                         break;
  1239.  
  1240.                                 len = strlen(En_US.abbrev_month_names[i]);
  1241.                                 if (strncasecmp(buf,
  1242.                                                 En_US.abbrev_month_names[i],
  1243.                                                 len) == 0)
  1244.                                         break;
  1245.                         }
  1246.                         if (i == asizeof(En_US.month_names))
  1247.                                 return 0;
  1248.  
  1249.                         tm->tm_mon = i;
  1250.                         buf += len;
  1251.                         break;
  1252.  
  1253.                 case 'm':
  1254.                         if (!isdigit(*buf))
  1255.                                 return 0;
  1256.  
  1257.                         for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
  1258.                                 i *= 10;
  1259.                                 i += *buf - '0';
  1260.                         }
  1261.                         if (i < 1 || i > 12)
  1262.                                 return 0;
  1263.  
  1264.                         tm->tm_mon = i - 1;
  1265.  
  1266.                         if (*buf != 0 && isspace(*buf))
  1267.                                 while (*ptr != 0 && !isspace(*ptr))
  1268.                                         ptr++;
  1269.                         break;
  1270.  
  1271.                 case 'Y':
  1272.                 case 'y':
  1273.                         if (*buf == 0 || isspace(*buf))
  1274.                                 break;
  1275.  
  1276.                         if (!isdigit(*buf))
  1277.                                 return 0;
  1278.  
  1279.                         for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
  1280.                                 i *= 10;
  1281.                                 i += *buf - '0';
  1282.                         }
  1283.                         if (c == 'Y')
  1284.                                 i -= 1900;
  1285.                         if (i < 0)
  1286.                                 return 0;
  1287.  
  1288.